package cn.itcast.account.service.impl;

import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountTCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author WDs , wds8.24@outlook.com
 * @version 1.0
 * @since 2024-05-18 15:36
 */
@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {
    @Resource
    private AccountMapper accountMapper;

    @Resource
    private AccountFreezeMapper accountFreezeMapper;

    @Override
    public void deduct(String userId, int money) {
        // 从Seata上下文中获取事务ID
        String xid = RootContext.getXID();
        // 悬挂
        AccountFreeze suspensionFreeze = accountFreezeMapper.selectById(xid);
        if (suspensionFreeze != null) {
            return;
        }
        // 扣减余额，创建冻结对象，记录状态并存储
        accountMapper.deduct(userId, money);
        AccountFreeze accountFreeze = new AccountFreeze();
        accountFreeze.setUserId(userId);
        accountFreeze.setFreezeMoney(money);
        accountFreeze.setState(AccountFreeze.State.TRY);
        accountFreeze.setXid(xid);

        accountFreezeMapper.insert(accountFreeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        String xid = ctx.getXid();
        int count = accountFreezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        String xid = ctx.getXid();
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        // 空回滚
        if (accountFreeze == null) {
            AccountFreeze freeze = new AccountFreeze();
            freeze.setXid(xid);
            freeze.setState(AccountFreeze.State.CANCEL);
            int count = accountFreezeMapper.insert(freeze);
            return count == 1;
        }
        // 幂等性
        if (accountFreeze.getState() == AccountFreeze.State.CANCEL) {
            return true;
        }
        // 常规回滚
        accountMapper.refund(accountFreeze.getUserId(), accountFreeze.getFreezeMoney());
        accountFreeze.setFreezeMoney(0);
        accountFreeze.setState(AccountFreeze.State.CANCEL);
        int account = accountFreezeMapper.updateById(accountFreeze);
        return account == 1;
    }
}
